<cfcomponent extends="Debug" output="no">

	<cfscript>
	  fields=array(
group("Execution Time","Execution times for templates, includes, modules, custom tags, and component method calls. Template execution times over this minimum highlight time appear in red.",2)
,field("Minimal Execution Time","minimal","0",true,{_appendix:"microseconds",_bottom:"Execution times for templates, includes, modules, custom tags, and component method calls. Outputs only templates taking longer than the time (in microseconds) defined above."},"text40")
,field("Highlight","highlight","250000",true,{_appendix:"microseconds",_bottom:"Highlight templates taking longer than the following (in microseconds) in red."},"text50")
,group("Display","Customize the data that or shown in the debugging.",2)
,field("Expression","expression","Enabled",false,"Enter expression to evaluate","checkbox","Enabled")
,field("General Debug Information ","general","Enabled",false,
"Select this option to show general information about this request. General items are Lucee Version, Template, Time Stamp, User Locale, User Agent, User IP, and Host Name. ",
"checkbox","Enabled")
,field("Callstack","callStack","Enabled",false,"Display callstack for templates","checkbox","Enabled")
,field("Percentages","displayPercentages","Enabled",false,"Display percentages for each entry","checkbox","Enabled")
,field("Highlight colored","colorHighlight","Enabled",true,"Color the output based on the overall percentages","checkbox","Enabled")
,field("Warn Session size","sessionSize","100",true,{_appendix:"KB",_bottom:"Warn in debugging, if the current session is above the following (in KB) size."},"text50")
);



		string function getLabel(){
			return "Modern";
		}

		string function getDescription(){
			return "The new style debug template";
		}

		string function getid(){
			return "lucee-modern";
		}

		void function onBeforeUpdate(struct custom){
			throwWhenNotNumeric(arguments.custom,"minimal");
			throwWhenNotNumeric(arguments.custom,"highlight");
		}

		private void function throwWhenEmpty(struct custom, string name){
			if(!structKeyExists(arguments.custom, arguments.name) or len(trim(arguments.custom[arguments.name])) EQ 0)
			throw "value for ["&arguments.name&"] is not defined";
		}

		private void function throwWhenNotNumeric(struct custom, string name){
			throwWhenEmpty(arguments.custom, arguments.name);
			if(!isNumeric(trim(arguments.custom[arguments.name])))
			throw "value for [" & arguments.name & "] must be numeric";
		}

		private function isColumnEmpty(query qry,string columnName){
			if(!QueryColumnExists(arguments.qry, arguments.columnName)) return true;
			return !len(arrayToList(queryColumnData(arguments.qry, arguments.columnName),""));
		}

		function isSectionOpen( string name ) {
			try {
				if ( arguments.name == "ALL" && !structKeyExists( Cookie, variables.cookieName ) )
					return true;

				var openSections = [];
				if ( structKeyExists( Cookie, variables.cookieName ) ) {
					try {
						openSections = deserializeJSON( Cookie[ variables.cookieName ] );
					} catch (any e) {
						openSections = [];
					}
				}
				return arrayFind(openSections, arguments.name) > 0;
			} catch (any e) {
				return false;
			}
		}

		function isEnabled( custom, key ) {

			return structKeyExists( arguments.custom, arguments.key ) 
				&& ( arguments.custom[ arguments.key ] == "Enabled" 
					|| arguments.custom[ arguments.key ] == "true" 
			);
		}


		variables.cookieName = "lucee_debug_modern";

		variables.scopeNames = [ "Application", "CGI", "Client", "Cookie", "Form", "Request", "Server", "Session", "URL" ];

		function buildSectionStruct(queries) {
			var otherSections = [ "ALL", "Dump", "ExecTime","TestTime", "ExecOrder", "Templates", "Exceptions", "ImpAccess", "Info", "Query", "Timer", "Trace", "More" ];
			if(!queryColumnExists(queries, "hash")) {
				queryAddColumn(queries, "hash",[]);
			}
			loop query=queries {
				var h = "h" & hash(queries.src & ":" & queries.line & ":" & queries.currentrow, "quick");
				arrayAppend(otherSections, h);
				querySetCell(queries, "hash", h,queries.currentrow);
			}
			
			
			var i = 0;

			var result = {};

			for ( var k in otherSections )
				result[ k ] = 2 ^ i++;

			for ( var k in variables.scopeNames )
				result[ k ] = 2 ^ i++;

			return result;
		}
	</cfscript>

	<cffunction name="output" returntype="void">
		<cfargument name="custom" type="struct" required="yes" />
		<cfargument name="debugging" required="true" type="struct" />
		<cfargument name="context" type="string" default="web" />
		<cfsilent>
<cfscript>

variables.chartStr = {};
if(structKeyExists(arguments.custom, "metrics_Charts")) {
	loop list=arguments.custom.metrics_Charts index="i" {
		if(i EQ "HeapChart")
			variables.chartStr[i] = "heap";
		else if(i EQ "NonHeapChart")
			variables.chartStr[i] = "nonheap";
		else if(i EQ "WholeSystem")
			variables.chartStr[i] = "cpuSystem";
	}
}
		if(!structKeyExists(arguments.custom,'minimal')) arguments.custom.minimal="0";
		if(!structKeyExists(arguments.custom,'highlight')) arguments.custom.highlight="250000";
		if(!structKeyExists(arguments.custom,'scopes')) arguments.custom.scopes=false;
		if(!structKeyExists(arguments.custom,'general'))arguments.custom.general="Enabled";

		if(isNull(arguments.debugging.pages)) 
			local.pages=queryNew('id,count,min,max,avg,app,load,query,total,src');
		else local.pages=arguments.debugging.pages;

		if(isNull(arguments.debugging.queries)) 
			local.queries=queryNew('name,time,sql,src,line,count,datasource,usage,cacheTypes');
		else local.queries=arguments.debugging.queries;

		if(isNull(arguments.debugging.exceptions)) 
			local.exceptions=[];
		else local.exceptions=arguments.debugging.exceptions;

		if(isNull(arguments.debugging.timers)) 
			local.timers=queryNew('label,time,template');
		else local.timers=arguments.debugging.timers;

		if(isNull(arguments.debugging.traces)) 
			local.traces=queryNew('type,category,text,template,line,var,total,trace');
		else local.traces=arguments.debugging.traces;

		if(isNull(arguments.debugging.dumps)) 
			local.dumps=queryNew('output,template,line');
		else local.dumps=arguments.debugging.dumps;

		if(isNull(arguments.debugging.implicitAccess)) 
			local.implicitAccess=queryNew('template,line,scope,count,name');
		else local.implicitAccess=arguments.debugging.implicitAccess;

		if(isNull(arguments.debugging.dumps)) 
			local.dumps=queryNew('output,template,line');
		else local.dumps=arguments.debugging.dumps;

		local.times=arguments.debugging.times;

		var time=getTickCount();
		
		// CGI
		if(!isNull(arguments.debugging.scope.cgi)) local._cgi=arguments.debugging.scope.cgi;
		else if(!isNull(arguments.debugging.cgi)) local._cgi=arguments.debugging.cgi; 
		else local._cgi=cgi;
		
		this.allSections = this.buildSectionStruct(queries);
		var isExecOrder  = this.isSectionOpen( "ExecOrder" );

		if(isExecOrder) {
			querySort(pages,"id","asc");
		}
		else {
			querySort(pages,"avg","desc");
		}

</cfscript>

		<cfset querySort(implicitAccess,"template,line,count","asc,asc,desc") />
		<cfparam name="arguments.custom.unit" default="millisecond">
		<cfparam name="arguments.custom.color" default="black">
		<cfparam name="arguments.custom.bgcolor" default="white">
		<cfparam name="arguments.custom.font" default="Times New Roman">
		<cfparam name="arguments.custom.size" default="medium">
		<cfset var unit={
			millisecond:"ms"
			,microsecond:"µs"
			,nanosecond:"ns"
			} />

		<cfset var ordermap={}>
		<cfloop query="#arguments.debugging.history#">
			<cfif !structkeyExists(ordermap, arguments.debugging.history.id)><cfset ordermap[ arguments.debugging.history.id ]=structCount(ordermap)+1></cfif>
		</cfloop>
		<cfset var prettify=structKeyExists(arguments.custom,'timeformat') and arguments.custom.timeformat EQ "natural">
		</cfsilent>


		<cfif arguments.context EQ "web">
			</td></td></td></th></th></th></tr></tr></tr></table></table></table></a></abbrev></acronym></address></applet></au></b></banner></big></blink></blockquote></bq></caption></center></cite></code></comment></del></dfn></dir></div></div></dl></em></fig></fn></font></form></frame></frameset></h1></h2></h3></h4></h5></h6></head></i></ins></kbd></listing></map></marquee></menu></multicol></nobr></noframes></noscript></note></ol></p></param></person></plaintext></pre></q></s></samp></script></select></small></strike></strong></sub></sup></table></td></textarea></th></title></tr></tt></u></ul></var></wbr></xmp>
		</cfif>
		<style type="text/css">
	#-lucee-debugging-ExecTime table.details th::after, #-lucee-debugging-ImpAccess table.details th::after { content: '\00A0\21E9';}
	#-lucee-debugging-ExecTime table.details th, #-lucee-debugging-ImpAccess table.details th { cursor:pointer; } 
	.sortby {text-decoration: underline; font-weight: bold;}

	.-lucee-icon-plus {
		background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='9' viewBox='0 0 9 9'%3E%3Crect x='0.5' y='0.5' width='8' height='8' fill='none' stroke='black' stroke-width='1'/%3E%3Crect x='2' y='4' width='5' height='1' fill='black'/%3E%3Crect x='4' y='2' width='1' height='5' fill='black'/%3E%3C/svg%3E")
			no-repeat left center;
  		padding: 4px 0 4px 16px;
  		background-size:10px 10px;
	}

	.-lucee-icon-minus {
  		background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='9' viewBox='0 0 9 9'%3E%3Crect x='0.5' y='0.5' width='8' height='8' fill='none' stroke='black' stroke-width='1'/%3E%3Crect x='2' y='4' width='5' height='1' fill='black'/%3E%3C/svg%3E")
    		no-repeat left center;
  		padding: 4px 0 4px 16px;
  		background-size: 10px 10px;
	}
	</style>






		<cfoutput>

			<cfset var sectionId = "ALL">
			<cfset var isOpen = this.isSectionOpen( sectionId )>

<!----------------------------------------
--------------- DEBUG ------------------
------------------------------------------
--->

				<div id="-lucee-debugging-ALL">

					<!--- General --->
					<cfif isEnabled( arguments.custom, 'general' )>

						<div class="section-title">Debugging Information</div>
					    <cfif getJavaVersion() LT 8 >
							<div class="warning">
								You are running Lucee with Java #server.java.version# Lucee does not formally support this version of Java. Consider updating to the latest Java version for security and performance reasons.
							</div>
					    </cfif>

						<cfset sectionId = "Info">
						<cfset isOpen = this.isSectionOpen( sectionId )>
						<table>

							<cfset renderSectionHeadTR( sectionId, "Template:", "#HTMLEditFormat(_cgi.SCRIPT_NAME)# (#HTMLEditFormat(expandPath(_cgi.SCRIPT_NAME))#)" )>

							<tr>
								<td class="pad label">User Agent:</td>
								<td class="pad">#_cgi.http_user_agent#</td>
							</tr>
							<tr>
								<td colspan="2" id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="ml14px">
										<tr>
											<td class="label" colspan="2">
												#server.coldfusion.productname#
												<cfif StructKeyExists(server.lucee,'versionName')>(<a href="#server.lucee.versionNameExplanation#" target="_blank">#server.lucee.versionName#</a>)
												</cfif>
												#ucFirst(server.coldfusion.productlevel)# #server.lucee.version# (CFML Version #server.ColdFusion.ProductVersion#)
											</td>
										</tr>
										<tr>
											<td class="label">Time Stamp</td>
											<td class="cfdebug">#LSDateFormat(now())# #LSTimeFormat(now())#</td>
										</tr>
										<tr>
											<td class="label">Time Zone</td>
											<td class="cfdebug">#getTimeZone()#</td>
										</tr>
										<tr>
											<td class="label">Locale</td>
											<td class="cfdebug">#ucFirst(GetLocale())#</td>
										</tr>
										<tr>
											<td class="label">Remote IP</td>
											<td class="cfdebug">#_cgi.remote_addr#</td>
										</tr>
										<tr>
											<td class="label">Host Name</td>
											<td class="cfdebug">#_cgi.server_name#</td>
										</tr>
										<cfif StructKeyExists(server.os,"archModel") and StructKeyExists(server.java,"archModel")>
											<tr>
												<td class="label">Architecture</td>
												<td class="cfdebug">
													<cfif server.os.archModel NEQ server.os.archModel>
														OS #server.os.archModel#bit/JRE #server.java.archModel#bit
													<cfelse>
														#server.os.archModel#bit
													</cfif>
												</td>
											</tr>
										</cfif>
									</table>
								</td>
							</tr>
						</table>
					</cfif>

					<!--- Abort --->
					<cfif structKeyExists(arguments.debugging,"abort")>
						<div class="section-title">Abort</div>
						<table>
							<tr>
								<td class="pad txt-r">#arguments.debugging.abort.template#:#arguments.debugging.abort.line#</td>
							</tr>
						</table>
					</cfif>

					<!--- Execution Time --->
					<cfset sectionId = "ExecTime">
					<cfset isOpen = this.isSectionOpen( sectionId )>

					<div class="section-title">Execution Time</div>
					<cfscript>
					local.loa=0;
					if(pages.recordcount) {
						local.tot=0;
						local.showLoad=true;
						loop query="pages" {
							tot=tot+pages.total;
							if(pages.avg LT arguments.custom.minimal*1000)
								continue;

							local.bad=pages.avg GTE arguments.custom.highlight*1000;
							loa=loa+pages.load;
						}
					}
					else {
						local.showLoad=false;
						local.tot=local.times.total;
					}
					</cfscript>

					<table>
						<cfset renderSectionHeadTR( sectionId
							, "<b>#unitFormat( arguments.custom.unit, tot, prettify )# ms
								&nbsp;&nbsp;&nbsp;&nbsp; Total</b>" )>

						<tr><td></td></tr>
						<tr>
							<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
								<table>
							<cfif showLoad>
							<tr>
								<td class="pad txt-r">#unitFormat( arguments.custom.unit, loa,prettify )# ms</td>
								<td class="pad">Startup/Compilation</td>
							</tr>
							</cfif>
							<tr>
								<td class="pad txt-r">#unitFormat( arguments.custom.unit, tot-times.query-loa,prettify )# ms</td>
								<td class="pad">Application</td>
							</tr>
							<tr>
								<td class="pad txt-r">#unitFormat( arguments.custom.unit, times.query,true )# ms</td>
								<td class="pad">Query</td>
							</tr>
						</table>
							</td><!--- #-lucee-debugging-#sectionId# !--->
						</tr>
					</table>

					<!--- Template --->
					<cfif pages.recordcount>

						<cfset sectionId = "Templates">
						<cfset isOpen = this.isSectionOpen( sectionId )>

						<div class="section-title">Templates</div>
						<table>

							<cfset renderSectionHeadTR( sectionId, 
								"#pages.recordcount# Template#pages.recordcount GT 1 ? 's' : ''# Executed" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="details">
									<thead>
									<tr>
										<th>Total (ms)</th>
										<th>Load (ms)</th>
										<th>App (ms)</th>
										<cfif queries.recordcount><th>Query (ms)</th></cfif>
										<th>Count</th>
										<th><cfif isExecOrder><a onclick="__LUCEE.debug.clearFlag( 'ExecOrder' ); __LUCEE.util.addClass( this, 'selected' );" class="sortby" title="Order by Avg Time (starting with the next request)">Avg</a><cfelse>Average</cfif> (ms)</th>
										<th>Template</th>
										<th><cfif isExecOrder>Order<cfelse><a onclick="__LUCEE.debug.setFlag( 'ExecOrder' ); __LUCEE.util.addClass( this, 'selected' );" class="sortby" title="Order by ID (starting with the next request)">Order</a></cfif></th>
									</tr>
									</thead>
									<cfset loa=0>
									<cfset tot=0>
									<cfset q=0>
									<cfset var hasBad = false>
									<tbody>
										<cfloop query="pages">
											<cfset tot=tot+pages.total>
											<cfset q=q+pages.query>
											<cfif pages.avg LT arguments.custom.minimal * 1000>
												<cfcontinue>
											</cfif>
											<cfset bad=pages.avg GTE arguments.custom.highlight * 1000>
											<cfif bad>
												<cfset hasBad = true>
											</cfif>
											<cfset loa=loa+pages.load>
											<tr class="nowrap #bad ? 'red' : ''#">
												<td class="txt-r" title="#pages.total#">#unitFormat(arguments.custom.unit, pages.total,true)#</td>
												<td class="txt-r" title="#pages.load#">#unitFormat(arguments.custom.unit, pages.load,true)#</td>
												<td class="txt-r" title="#pages.app#">#unitFormat(arguments.custom.unit, pages.app,true)#</td>
												<cfif queries.recordcount><td class="txt-r" title="#pages.query#">#unitFormat(arguments.custom.unit, pages.query,true)#</td></cfif>
												<td class="txt-r">#pages.count#</td>
												<td class="txt-r" title="#pages.avg#"><cfif pages.count GT 1>#unitFormat(arguments.custom.unit, pages.avg,true)#<cfelse>-</cfif></td>
												<td id="-lucee-debugging-pages-#pages.currentRow#" oncontextmenu="__LUCEE.debug.selectText( this.id );">#pages.src#</td>
												<td class="txt-r faded" title="#pages.id#">#ordermap[pages.id]#</td>
											</tr>
										</cfloop>
									</tbody>
									<cfif hasBad>
										<tfoot>
											<tr class="red">
												<td colspan="5">red = over #unitFormat( arguments.custom.unit, arguments.custom.highlight * 1000 ,true)# ms average execution time</td>
											</tr>
										</tfoot>
									</cfif>
								</table>
								</td>
							</tr>
						</table>
					</cfif>










					<!--- Exceptions --->
					<cfif structKeyExists( local, "exceptions" ) && arrayLen( local.exceptions )>

						<cfset sectionId = "Exceptions">
						<cfset isOpen = this.isSectionOpen( sectionId )>

						<div class="section-title">Caught Exceptions</div>
						<table>

							<cfset renderSectionHeadTR( sectionId, "#arrayLen(local.exceptions)# Exception#arrayLen( local.exceptions ) GT 1 ? 's' : ''# Caught" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="details">
									<thead>
										<tr>
											<th>Type</th>
											<th>Message</th>
											<th>Detail</th>
											<th>Template</th>
											<th>Line</th>
										</tr>
									</thead>
									<tbody>
										<cfloop array="#local.exceptions#" index="local.exp">
											<tr>
												<td>#exp.type#</td>
												<td>#exp.message#</td>
												<td>#exp.detail#</td>
												<cfif arrayLen(exp.TagContext) gt 0>
													<td>#exp.TagContext[1].template#</td>
													<td class="txt-r">#exp.TagContext[1].line#</td>
												</cfif>
											</tr>
										</cfloop>
									</tbody>
									</table>
								</td><!--- #-lucee-debugging-#sectionId# !--->
							</tr>
						</table>
					</cfif>

					<!--- Implicit variable Access --->
					<cfif implicitAccess.recordcount>

						<cfset sectionId = "ImpAccess">
						<cfset isOpen = this.isSectionOpen( sectionId )>

						<div class="section-title">Implicit Variable Access</div>

						<table>
							<cfset renderSectionHeadTR( sectionId, "#implicitAccess.recordcount# Implicit Variable Access#( implicitAccess.recordcount GT 1 ) ? 'es' : ''#" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="details">
									<thead>
										<tr>
											<th>Template</th>
											<th>Line</th>
											<th>Scope</th>
											<th>Var</th>
											<th>Count</th>
										</tr>
									</thead>
									<cfset variables.total=0 />
									<tbody>
										<cfloop query="implicitAccess">
											<tr>
												<td>#implicitAccess.template#</td>
												<td class="txt-r">#implicitAccess.line#</td>
												<td>#implicitAccess.scope#</td>
												<td>#implicitAccess.name#</td>
												<td class="txt-r">#implicitAccess.count#</td>
											</tr>
										</cfloop>
									<tbody>
									</table>
								</td><!--- #-lucee-debugging-#sectionId# !--->
							</tr>
						</table>
					</cfif>

					<!--- Timers --->
					<cfif timers.recordcount>

						<cfset sectionId = "Timer">
						<cfset isOpen = this.isSectionOpen( sectionId )>

						<div class="section-title">CFTimer Times</div>

						<table>

							<cfset renderSectionHeadTR( sectionId, "#timers.recordcount# Timer#( timers.recordcount GT 1 ) ? 's' : ''# Set" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="details">
									<thead>
										<tr>
											<th align="center">Label</th>
											<th>Time (ms)</th>
											<th>Template</th>
										</tr>
									<tbody>
										<cfloop query="timers">
											<tr>
												<td class="txt-r">#timers.label#</td>
												<td class="txt-r">#unitFormat( arguments.custom.unit, timers.time * 1000000,prettify )#</td>
												<td class="txt-r">#timers.template#</td>
											</tr>
										</cfloop>
									</tbody>
									</table>
								</td><!--- #-lucee-debugging-#sectionId# !--->
							</tr>
						</table>
					</cfif>

					<!--- Traces --->
					<cfif traces.recordcount>

						<cfset sectionId = "Trace">
						<cfset isOpen = this.isSectionOpen( sectionId )>

						<div class="section-title">Trace Points</div>

						<cfset hasAction=!isColumnEmpty(traces,'action') />
						<cfset hasCategory=!isColumnEmpty(traces,'category') />

						<table>

							<cfset renderSectionHeadTR( sectionId, "#traces.recordcount# Trace Point#( traces.recordcount GT 1 ) ? 's' : ''#" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="details">
									<thead>
										<tr>
											<th>Type</th>
											<cfif hasCategory>
												<th>Category</th>
											</cfif>
											<th>Text</th>
											<th>Template</th>
											<th>Line</th>
											<cfif hasAction>
												<th>Action</th>
											</cfif>
											<th>Var</th>
											<th>Total Time (ms)</th>
											<th>Trace Slot Time (ms)</th>
										</tr>
									</thead>
									<cfset total=0 />
									<tbody>
										<cfloop query="traces">
											<cfset total=total+traces.time />
											<tr>
												<td>#traces.type#</td>
												<cfif hasCategory>
													<td>#traces.category#&nbsp;</td>
												</cfif>
												<td>#traces.text#&nbsp;</td>
												<td>#traces.template#</td>
												<td class="txt-r">#traces.line#</td>
												<cfif hasAction>
													<td>#traces.action#</td>
												</cfif>
												<td>
													<cfif len(traces.varName)>
														#traces.varName#
														<cfif structKeyExists(traces,'varValue')>
															= #traces.varValue#
														</cfif>
													<cfelse>
														&nbsp;
														<br />
													</cfif>
												</td>
												<td class="txt-r">#unitFormat(arguments.custom.unit, total,prettify)#</td>
												<td class="txt-r">#unitFormat(arguments.custom.unit, traces.time,prettify)#</td>
											</tr>
										</cfloop>
									</tbody>

									</table>
								</td><!--- #-lucee-debugging-#sectionId# !--->
							</tr>
						</table>
					</cfif>

					<!--- Dumps --->
					<cfif dumps.recordcount>

						<cfset sectionId = "Dump">
						<cfset isOpen = this.isSectionOpen( sectionId )>

						<div class="section-title">Dumps</div>


						<table>

							<cfset renderSectionHeadTR( sectionId, "#dumps.recordcount# Dump#( dumps.recordcount GT 1 ) ? 's' : ''#" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">
									<table class="details">
									<thead>
										<tr>
											<th>Output</th>
											<th>Template</th>
											<th>Line</th>
										</tr>
									</thead>
										<cfset total=0 />
									<tbody>
										<cfloop query="dumps">
											<tr>
												<td>#dumps.output#</td>
												<td>#dumps.template#</td>
												<td class="txt-r">#dumps.line#</td>
											</tr>
										</cfloop>
									</tbody>
									</table>
								</td>
							</tr>
						</table>
					</cfif>

					<!--- Queries --->
					<cfif queries.recordcount>

						<cfset sectionId = "Query">
						<cfset isOpen = this.isSectionOpen( sectionId )>
						<cfset local.total  =0>
						<cfset local.records=0>
						<cfset local.openConns=0>
						<cfloop struct="#arguments.debugging.datasources#" index="dsn" item="item">
							<cfset local.openConns=item.openConnections>
						</cfloop>

						<cfloop query="queries">
							<cfset total   += queries.time>
							<cfset records += queries.count>
						</cfloop>
						<div class="section-title">Datasource Information</div>
						<table>
							<cfset renderSectionHeadTR( sectionId, "#queries.recordcount# Quer#queries.recordcount GT 1 ? 'ies' : 'y'# Executed (Total Records: #records#; Total Time: #unitFormat( arguments.custom.unit, total ,prettify)# ms; Total Open Connections: #openConns#)" )>

							<tr>
								<td id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'#">


									<table><tr><td>
										<b>General</b>
										<table class="details">
										<thead>											
											<tr>
												<th>Name</th>
												<th>Open Connections</th>
												<th>Max Connections</th>
											</tr>
										</thead>
										<tbody>
											<cfloop struct="#arguments.debugging.datasources#" index="local.dsName" item="local.dsData">
												<tr>
													<td class="txt-r">#dsData.name#</td>
													<td class="txt-r">#dsData.openConnections#</td>
													<td class="txt-r">#dsData.connectionLimit==-1?'INF':dsData.connectionLimit#</td>
												</tr>											
											</cfloop>
										</tbody>
										</table>
									<cfset hasCachetype=ListFindNoCase(queries.columnlist,"cachetype") gt 0>
									<br><b>SQL Queries</b>
									<table class="details">
											<thead>
												<tr>
													<th>&nbsp;</th>
													<th>Name</th>
													<th>Records</th>
													<th>Time</th>
													<th>Usage</th>
													<th>Datasource</th>
													<th>Source</th>
													<th>Line</th>
													<cfif hasCachetype><th>Cached</th></cfif>
												</tr>
											</thead>
										<cfloop query="queries">
											<cfset local.doUsage=listFindNoCase(queries.columnlist, 'usage') && isStruct(queries.usage)>
											<cfif doUsage>
												<cfscript>
													local.usageNotRead = [];
													local.usageRead = [];
													loop collection="#queries.usage#" index="local.item" item="local.value" {
														if ( !local.value )
															arrayAppend( usageNotRead, item );
														else
															arrayAppend( usageRead, item );
													}
													local.lenUsed = arrayLen( usageRead );
													local.lenNotUsed = arrayLen( usageNotRead );
													local.cols = local.lenNotUsed + local.lenUsed;

													if ( lenNotUsed == 0 || cols == 0 )
														local.usage = 100;
													else
														local.usage = (local.lenUsed / local.cols) * 100;
													local.highlightUnused = true;
													if ( queries.count == 0 )
														local.highlightUnused = false;
													else if ( local.usage == 100 )
														local.highlightUnused = false;
													
												</cfscript>
									
											</cfif>	
											<tbody>
												<cfset sectionId = queries.hash>
												<cfset isOpen = this.isSectionOpen( sectionId )>
												<tr>
													<td><cfset renderSectionA( sectionId, "" )></td>
													<td><cfset renderSectionA( sectionId, queries.name,"",false)></td>
													<td class="txt-r">#queries.count#</td>
													<td class="txt-r">#unitFormat(arguments.custom.unit, queries.time,prettify)# ms</td>
													<td class="txt-r<cfif doUsage and usage lt 100> warning<cfelseif doUsage and usage eq 100> happy</cfif>"><cfif doUsage>#int(usage)#%<cfelse>-</cfif></td>
													<td>#queries.datasource#</td>
													<td>#queries.src#</td>
													<td>#queries.line#</td>
													<cfif hasCachetype><td>#YesNoFormat(!isEmpty(queries.cacheType))#</td></cfif>
												</tr>
												<tr class="sort-group">
													<td colspan="9" 
													id="-lucee-debugging-#sectionId#"
													class="#isOpen ? '' : 'collapsed'#"
													oncontextmenu="__LUCEE.debug.selectText( this.id );">
													<div class="inner">
														<cfset hasParams=!isEmpty(queries.paramValue) && !isEmpty(queries.paramType)>
														<span class="bold">SQL<cfif hasParams> (Merged Parameters)</cfif></span>
														<div class="innercircle">
															<span class="prey">#trim( queries.sql )#</span>
														</div>
														<cfif hasParams>
															<br><span class="bold">SQL (Explicit Parameters)</span>
															<div class="innercircle">
																<span class="prey">#trim( queries.sqlPattern )#</span>
															</div
														</cfif>



													</div>													

													<cfif doUsage>
													<div class="inner">
														<cfif usage EQ 100>
															<span class="bold">Query column usage</span><br>
															<span class="happy">All columns are used</span><br>
														<cfelseif usage EQ 0>
															<span class="bold">Query column usage</span><br>
															<span class="warning">None of the columns are used</span><br>
														<cfelse>
															<span class="bold">Query column usage</span><br>
															<cfif lenNotUsed>
															<span class="warning">
																the following columns are NOT used:
																<cfloop from="1" to="#lenNotUsed#" index="local.ii">
																	<li>#usageNotRead[ ii ]#
																</cfloop>
															</span>
														
															</cfif>
														</cfif>
													</cfif>
													</div>
													</td>
												</tr>
											</tbody>
										</cfloop>
										</table>

									</tr></td></table>
								</td><!--- #-lucee-debugging-#sectionId# !--->
							</tr>
						</table>
					</cfif>

					<!--- Scopes --->
					<cfif isEnabled( arguments.custom, "scopes" )>

						<cfset local.scopes = variables.scopeNames>

						<cfset local.appSettings = getApplicationSettings()>
						<cfset local.isScopeEnabled = true>

						<div class="section-title">Scope Information</div>
						<table cellpadding="0" cellspacing="0">

							<cfloop array="#local.scopes#" index="local.k">

								<tr><td style="font-size: 4px;">&nbsp;</td></tr>

								<cfset sectionId = k>
								<cfswitch expression="#k#">

									<cfcase value="Client">

										<cfset isScopeEnabled = local.appSettings.clientManagement>
									</cfcase>
									<cfcase value="Session">

										<cfset isScopeEnabled = local.appSettings.sessionManagement>
									</cfcase>
									<cfdefaultcase>

										<cfset isScopeEnabled = true>
									</cfdefaultcase>
								</cfswitch>

								<cfif isScopeEnabled>

									<cfset isOpen = this.isSectionOpen( sectionId )>
									<cfset local.v = evaluate( k )>
									<cfset local.sc = structCount( v )>

									<cftry>

										<cfset local.estSize = byteFormat( sc == 0 ? 0 : sizeOf( v ) )>

										<cfcatch>

											<cfset local.estSize = "not available">
										</cfcatch>
									</cftry>

									<cfset renderSectionHeadTR( sectionId, "<b>#k# Scope</b> #sc ? '(~#estSize#)' : '(Empty)' #" )>

									<tr><td colspan="3">

										<table id="-lucee-debugging-#sectionId#" class="#isOpen ? '' : 'collapsed'# ml14px"><tr><td>

											<cfif isOpen>
												<cftry><cfdump var="#v#" keys="1000" label="#sc GT 1000?"First 1000 Records":""#"><cfcatch>not available</cfcatch></cftry>
											<cfelse>
												the Scope will be displayed with the next request
											</cfif>
										</td></tr></table><!--- #-lucee-debugging-#sectionId# !--->
									</td></tr>
								<cfelse>

									<tr>
										<td class="faded" style="padding-left: 16px;"><b>#k# Scope</b> (Not Enabled for this Application)</td>
									</tr>
								</cfif>
							</cfloop>

						</table>
					</cfif>

				</div>
			
		</cfoutput>


		<script>
			<cfset this.includeInline( "/lucee/res/js/util.min.js" )>

			var __LUCEE = __LUCEE || {};

			__LUCEE.debug = {

				<cfoutput>
				  cookieName: 	"#variables.cookieName#"
				</cfoutput>

				, toggleSection:	function( name ) {

					var btn = __LUCEE.util.getDomObject( "-lucee-debugging-btn-" + name );
					var obj = __LUCEE.util.getDomObject( "-lucee-debugging-" + name );
					var openSections = [];
					try {
						openSections = JSON.parse( __LUCEE.util.getCookie(__LUCEE.debug.cookieName) || "[]" );
						if ( !Array.isArray( openSections ) ) openSections = [];
					} catch(e) {
						openSections = [];
					}
					var idx = openSections.indexOf (name );
					var isOpen = idx > -1;

					if ( isOpen ) {
						openSections.splice( idx, 1 );
						__LUCEE.util.removeClass( btn, '-lucee-icon-minus' );
						__LUCEE.util.addClass( btn, '-lucee-icon-plus' );
						__LUCEE.util.addClass( obj, 'collapsed' );
					} else {

						openSections.push( name );
						__LUCEE.util.removeClass( btn, '-lucee-icon-plus');
						__LUCEE.util.addClass( btn, '-lucee-icon-minus' );
						__LUCEE.util.removeClass( obj, 'collapsed' );
					}
					__LUCEE.util.setCookie( __LUCEE.debug.cookieName, JSON.stringify(openSections) );
					return !isOpen;
				}

				, selectText:	__LUCEE.util.selectText
				, sortTable:		function (th, sortDefault){					
					var tr = th.parentElement;
					var table = tr.parentElement.parentElement; // table;
					var tbodys = table.getElementsByTagName("tbody");
					var theads = table.getElementsByTagName("thead");
					var rowspans = (table.dataset.rowspan !== "false");

					if (!th.dataset.type)
						th.dataset.type = sortDefault; // otherwise text
					if (!th.dataset.dir){
						th.dataset.dir = "asc";
					} else {
						if (th.dataset.dir == "desc")
							th.dataset.dir = "asc";
						else
							th.dataset.dir = "desc";
					}
					for (var h = 0; h < tr.children.length; h++){
						var cell = tr.children[h].style;
						if (h === th.cellIndex){
							cell.fontWeight = 700;
							cell.fontStyle = (th.dataset.dir == "desc") ? "normal" : "italic";
						} else {
							cell.fontWeight = 300;
							cell.fontStyle = "normal";
						}
					}
					var sortGroup = false;
					var localeCompare = "test".localeCompare ? true : false;
					var data = [];

					for ( var b = 0; b < tbodys.length; b++ ){
						var tbody =tbodys[b];
						for ( var r = 0; r < tbody.children.length; r++ ){
							var row = tbody.children[r];
							var group = false;
							if (row.classList.length > 0){
								// check for class sort-group
								group = row.classList.contains("sort-group");
							}
							// this is to handle secondary rows with rowspans, but this stops two column tables from sorting
							if (group){
								data[data.length-1][1].push(row);
							} else {
								switch (row.childElementCount){
									case 0:
									case 1:
										continue;
									case 2:
										if (!rowspans)
											break;
										if (data.length > 1)
											data[data.length-1][1].push(row);										
										continue;
									default:
										break;
								}								
								var cell = row.children[th.cellIndex];
								var val = cell.innerText;
								if (localeCompare){
									// hack to handle formatted numbers with commas for thousand separtors
									var tmpNum = val.split(",");
									if (tmpNum.length > 1){
										tmpNum = Number(tmpNum.join(""));
										if (tmpNum !== NaN)
											val = String(tmpNum);
									}
								} else {
									switch (th.dataset.type){
										case "text":
											val = val.toLowerCase();
											break;
										case "numeric":
										case "number":
											switch (val){
												case "":
												case "-":
													val = -1;
													break;
												default:
													val = Number(val);
												break;
											}
											break;
									}
								}
								var _row = row;
								if (r === 0 && 
										theads.length > 1 &&
										tbody.previousElementSibling.nodeName === "THEAD" && 
										tbody.previousElementSibling.children.length){
									data.push([val, [tbody.previousElementSibling, row], tbody]);
									sortGroup = true;
								} else {
									data.push([val, [row]]);
								}
								
							}
						}
					}

					switch (th.dataset.type){
						case "text":
							data = data.sort(function(a,b){
								if (localeCompare){
									return a[0].localeCompare(b[0],"kn",{numeric:true});
								} else {
									if (a[0] < b[0])
										return -1;
									if (a[0] > b[0])
										return 1;
									return 0;
								}                    
							});
							break;
						case "numeric": 
						case "number":
							data = data.sort(function(a,b){
								return a[0] - b[0];
							}); 
					}
					
					//console.log(data);
					if (th.dataset.dir === "asc")
						data.reverse();
					if (!sortGroup){
						for (r = 0; r < data.length; r++){
							for (var rr = 0; rr < data[r][1].length; rr++)
								tbody.appendChild(data[r][1][rr]);
						}						
					} else {
						for (r = 0; r < data.length; r++){
						
							if (data[r].length === 3){
								var _rows = data[r];
								table.appendChild(_rows[1][0]); // thead
								table.appendChild(_rows[2]); // tbody
								var _tbody = _rows[2];
								for (var rr = 1; rr < _rows[1].length; rr++)
									_tbody.appendChild(_rows[1][rr]); // tr
								
							} else {
								for (var rr = 0; rr < data[r][1].length; rr++)
									table.appendChild(data[r][1][rr]); 
							}
						}
					}

				}
			};
		</script>



	</cffunction><!--- output() !--->




	<cffunction name="renderSectionA" output="#true#">

		<cfargument name="sectionId">
		<cfargument name="label1">
		<cfargument name="label2" default="">
		<cfargument name="showIcon" default="#true#">

		<cfset var isOpen = this.isSectionOpen( arguments.sectionId )>
		<a id="-lucee-debugging-btn-#arguments.sectionId#" <cfif arguments.showIcon> class="-lucee-icon-#isOpen ? 'minus' : 'plus'#"</cfif> onclick="__LUCEE.debug.toggleSection( '#arguments.sectionId#' );">
				#arguments.label1#</a>
			<a onclick="__LUCEE.debug.toggleSection( '#arguments.sectionId#' );">#arguments.label2#</a>
	</cffunction>



	<cffunction name="renderSectionHeadTR" output="#true#">

		<cfargument name="sectionId">
		<cfargument name="label1">
		<cfargument name="label2" default="">
		<cfargument name="withTags" default="#true#">

		<cfset var isOpen = this.isSectionOpen( arguments.sectionId )>

		<tr>
			<td><a id="-lucee-debugging-btn-#arguments.sectionId#" class="-lucee-icon-#isOpen ? 'minus' : 'plus'#" onclick="__LUCEE.debug.toggleSection( '#arguments.sectionId#' );">
				#arguments.label1#</a></td>
			<td class="pad"><a onclick="__LUCEE.debug.toggleSection( '#arguments.sectionId#' );">#arguments.label2#</a></td>
		</tr>
	</cffunction>

	<cfscript>

		function unitFormat( string unit, numeric time, boolean prettify=false ) {
			/*if ( !arguments.prettify ) {
				return NumberFormat( arguments.time / 1000000, ",0.000" );
			}*/

			// display 0 digits right to the point when more or equal to 100ms
			//if ( arguments.time >= 100000000 )
			//	return int( arguments.time / 1000000 );

			// display 1 digit right to the point when more or equal to 10ms
			if ( arguments.time >=  10000000 )
				return ( int( arguments.time / 100000 ) / 10 );

			// display 2 digits right to the point when more or equal to 1ms
			if ( arguments.time >=   1000000 )
				return ( int( arguments.time / 10000 ) / 100 );

			// display 3 digits right to the point
			return ( int( arguments.time / 1000 ) / 1000 );

		}


		function byteFormat( numeric size ) {

			var values = [ [ 1099511627776, 'TB' ], [ 1073741824, 'GB' ], [ 1048576, 'MB' ], [ 1024, 'KB' ] ];

			for ( var i in values ) {

				if ( arguments.size >= i[ 1 ] )
					return numberFormat( arguments.size / i[ 1 ], '9.99' ) & i[ 2 ];
			}

			return arguments.size & 'B';
		}

		/** reads the file contents and writes it to the output stream */
		function includeInline(filename) cachedWithin=createTimeSpan(0,1,0,0) {

			echo(fileRead(expandPath(arguments.filename)));
		}

		function getJavaVersion() {
	        var verArr=listToArray(server.java.version,'.');
	        if(verArr[1]>2) return verArr[1];
	        return verArr[2];
	    }

	    function getAllFunctions() {
			var result = getFunctionList().keyArray().sort( 'textnocase' ).filter( function( el ) { return left( arguments.el, 1 ) != '_'; } );
			return result;
		}

		function getAllTags() {
			var result = [];
			var itemList = getTagList();
			for ( local.ns in itemList.keyArray() ) {
				for ( local.key in itemList[ ns ].keyArray() ) {
					result.append( ns & key );
				}
			}
			result.sort( 'textnocase' );
			return result;
		}

		function  getAllComponents() localmode=true {
			// getting available component packages
			tmpStr.componentDetails={};
			tmpStr.componentDetails.pack=["org.lucee.cfml"];

			arraySort(tmpStr.componentDetails.pack, "textnocase");
			tmpStr.componentDetails.cfcs=[];
			for(index=tmpStr.componentDetails.pack.len();index>0;index--) {
				currPack=tmpStr.componentDetails.pack[index];
				try{
					var tmpComponents=ComponentListPackage(currPack);
				}
				catch(e) {
					arrayDeleteAt(tmpStr.componentDetails.pack,index);
					continue;
				}

				for(i=1;i<=tmpComponents.len();i++){
					tmpComponents[i]=currPack&"."&tmpComponents[i];
				}
				if(tmpComponents.len()==0) {
					arrayDeleteAt(tmpStr.componentDetails.pack,index);
					continue;
				}
				else arrayAppend(tmpStr.componentDetails.cfcs, tmpComponents, true);
			}
			arraySort(tmpStr.componentDetails.cfcs, "textnocase");

			return tmpStr.componentDetails.cfcs;
		}

	</cfscript>


</cfcomponent>